home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / BCCAPP.ARJ / POPUP.C < prev    next >
C/C++ Source or Header  |  1991-09-15  |  8KB  |  380 lines

  1. /*
  2.  *
  3.  * Class Implementation for Popup menu system
  4.  *
  5.  * (C) 1990 Vision Software
  6.  *
  7.  * $Id: popup.c 1.2001 91/04/25 15:07:51 pcalvin release $
  8.  *
  9.  * Comments:
  10.  *
  11.  * Superclass POPUP menus.  This class provides popup menuing capabilities.
  12.  * In addition, we have the base class for all scroll/menus etc..
  13.  *
  14.  * Bugs:
  15.  *
  16.  * None documented
  17.  *
  18.  */
  19. #include <stdlib.h>
  20. #include <conio.h>
  21. #include <string.h>
  22. #include <ctype.h>
  23. #include <dos.h>
  24.  
  25. #include <stdhdr.h>
  26. #include <adl.h>
  27. #include <menu.h>
  28.  
  29. #include "lowlevel.h"
  30.  
  31. /*
  32.  * Public constructors, used by the general public for
  33.  * Straight forward popup menus..
  34.  */
  35. POPUP::POPUP(ROW row,COL col,CENT centMenu,PENT pentMenu,SZ sz) : help(szNil)
  36.     {
  37.     cchMenuMax = cchNil;
  38.     rowTop = row;
  39.     colLeft = col;
  40.     centMax = centMenu;
  41.     pentBase = pentMenu;
  42.     szTitle = sz;
  43.     }
  44.  
  45. /*
  46.  * Protected constructors.  These are used by the Pulldown system
  47.  * and others to build popups as needed.
  48.  */
  49. POPUP::POPUP(SZ sz) : help(szNil)
  50.     {
  51.     cchMenuMax = cchNil;
  52.     pentBase = pentNil;
  53.     szTitle = sz;
  54.     }
  55.  
  56. /*
  57.  * Get routine called by derived classes to adjust menu dynamically
  58.  */
  59. CENT POPUP::CentGet(ROW row,COL col,CENT cent,PENT pentMenu)
  60.     {
  61.     colLeft = col;
  62.     rowTop = row;
  63.     centMax = cent;
  64.     pentBase = pentMenu;
  65.     return (CentGet());
  66.     }
  67.  
  68. /*
  69.  * Answers with the key that exited the previous POPUP
  70.  */
  71. CD POPUP::CdExitKey(VOID)
  72.     {
  73.     return (cdLastKey);
  74.     }
  75.  
  76. /*
  77.  * Get routine available to the general public, popup must be set
  78.  * at declaration time..
  79.  */
  80. CENT POPUP::CentGet()
  81.     {
  82.     CURSOR crs(fFalse);
  83.  
  84.     /*
  85.      * Place popup on the screen if needed.
  86.      * Set flag to remove at end..
  87.      */
  88.     Show();
  89.  
  90.     if (pentBase != pentNil)
  91.         help.Replace(pentBase[centAnswer].szQuickHelp);
  92.  
  93.     /*
  94.      *    Loop until menu is terminated.
  95.      */
  96.     while (FHandleCd(centAnswer,cdLastKey = CdInput(),pentBase,wnd))
  97.         Display(centAnswer,pentBase,wnd,fTrue);
  98.  
  99.     /*
  100.      * An indication of the selected entry.  This flash is NOT done if 
  101.      *    the selected entry is the root of a sub-menu.  Otherwise, we
  102.      *    would have flashes all over the screen as sub-menus are unwound.
  103.      */
  104.     if (centAnswer != centError && pentBase[centAnswer].pentNext == pentNil)
  105.         Flash(centAnswer,pentBase,wnd);
  106.  
  107.     /*
  108.      * If this Get is not Re-entrant, remove it from the screen..
  109.      */
  110.     Hide();
  111.  
  112.     /*
  113.      * If a selection was made, attempt to call that function
  114.      */
  115.     if ((centAnswer != centError) && (pentBase != pentNil))
  116.         {
  117.         if (pentBase[centAnswer].pfnFunction != Nil)
  118.             pentBase[centAnswer].pfnFunction();
  119.         }
  120.  
  121.     return (centAnswer);
  122.     }
  123.  
  124. /*
  125.  * Puts popup onto the screen
  126.  */
  127. VOID POPUP::Show(VOID)
  128.     {
  129.     /*
  130.      *     Compute size of window and open it..
  131.      */
  132.     rowTop = RowTopFromCentPent(centMax,pentBase);
  133.     colLeft = ColLeftFromCentPent(centMax,pentBase);
  134.     rowBottom = CrowFromCentPent(centMax,pentBase) + rowTop+1;
  135.     colRight = CcolFromCentPent(centMax,pentBase) + colLeft+1;
  136.  
  137.     /*
  138.      *    Now, simply create the window..
  139.      */
  140.     wnd = WINDOW(rowTop+2,colLeft,rowBottom,colRight,coBlack,coCyan,szTitle);
  141.     wnd.Open();
  142.  
  143.     /*
  144.      * Fill in related information
  145.      */
  146.     Redraw();
  147.  
  148.     /*
  149.      * First member is selected
  150.      */
  151.     Display(centNil,pentBase,wnd,fTrue);
  152.     centAnswer = centNil;
  153.     }
  154.  
  155. /*
  156.  * Removes the popup from the screen..
  157.  */
  158. VOID POPUP::Hide(VOID)
  159.     {
  160.     wnd.Close();
  161.     }
  162.  
  163. /*
  164.  * Redraws the selections
  165.  */
  166. VOID POPUP::Redraw(VOID)
  167.     {
  168.     for (CENT cent = centNil; cent < centMax; cent++)
  169.         Display(cent,pentBase,wnd,fFalse);
  170.     }
  171.  
  172. /*
  173.  * Called by Redraw() to display individual entries..
  174.  */
  175. VOID POPUP::Display(CENT cent,PENT pent,WINDOW &rwnd,BOOL fSelected)
  176.     {
  177.     PointerAssert(pent);
  178.     PointerAssert(pent[cent].sz);
  179.  
  180.     CO coBack = fSelected ? coGreen : coCyan;
  181.     SZ sz = SzFromCentPent(cent,pent);
  182.     CCH cch = pent[cent].cchHotKey+1;
  183.  
  184.     rwnd.SayHot(cent,0,sz,cch,coBlack,coBack);
  185.     }
  186.  
  187. /*
  188.  * This is the base level handling for Keyboard input.  This virtual
  189.  * function answers if the input should continue.
  190.  * Additionally, the first formal parameter (CENT &rcent) answers with
  191.  * the new selected entry
  192.  */
  193. BOOL POPUP::FHandleCd(CENT &rcent,CD cd,PENT pent,WINDOW &rwnd)
  194.     {
  195.     BOOL fContinue = fTrue;
  196.     /*
  197.      * Defaults to no exit, must prove otherwise.
  198.      */
  199.     switch (cd)
  200.         {
  201.     case cdEscape:
  202.         /*
  203.          * The escape key, Unless trapped by a derived class
  204.          * Quits the popup..
  205.          */
  206.         rcent = centError;
  207.         fContinue = fFalse;
  208.         break;
  209.     case cdReturn:
  210.         /*
  211.          * If a derived class is not using the standard MENU entries,
  212.          * It had BETTER trap the return key.
  213.          * If they are not, the program will ASSERT right here.
  214.          */
  215.         Assert(pent != pentNil);
  216.         Assert(pent->sz != szNil);
  217.         /*
  218.          * If there is a sub-menu, display it..
  219.          */
  220.         if (pent[rcent].pentNext != pentNil)
  221.             {
  222.             fContinue = FSubMenuFromCentPent(rcent,pent);
  223.             }
  224.         else
  225.             {
  226.             cdLastKey = pent[rcent].sz[pent[rcent].cchHotKey];
  227.             fContinue = fFalse;
  228.             }
  229.         break;
  230.     case cdCursorUp:
  231.         if (rcent > 0)
  232.             {
  233.             Display(rcent,pent,rwnd,fFalse);
  234.             rcent -= 1;
  235.             help.Replace(pent[rcent].szQuickHelp);
  236.             }
  237.         break;
  238.     case cdCursorDown:
  239.         if (rcent+1 < centMax)
  240.             {
  241.             Display(rcent,pent,rwnd,fFalse);
  242.             rcent += 1;
  243.             help.Replace(pent[rcent].szQuickHelp);
  244.             }
  245.         break;
  246.     default:
  247.         if (pentBase != pentNil && isascii(cd))
  248.             {
  249.             CHAR ch = toupper(cd);
  250.  
  251.             for (CENT centKey = centNil; fContinue && centKey < centMax; centKey++)
  252.                 {
  253.                 /*
  254.                  *    Search array for matching key.
  255.                  */
  256.                 if (toupper(pent[centKey].sz[pent[centKey].cchHotKey]) == ch)
  257.                     {
  258.                     Display(rcent,pent,rwnd,fFalse);
  259.                     cdLastKey = (CD)pent[centKey].sz[pent[centKey].cchHotKey];
  260.                     rcent = centKey;
  261.  
  262.                     /*
  263.                      * If this menu has a sub-menu, move the highlight over the
  264.                      *    selected member and activate the sub-menu
  265.                      */
  266.                     if (pent[centKey].pentNext != pentNil)
  267.                         {
  268.                         Display(rcent,pent,rwnd,fTrue);
  269.                         fContinue = FSubMenuFromCentPent(centKey,pent);
  270.                         }
  271.                     else
  272.                         {
  273.                         fContinue = fFalse;
  274.                         }
  275.                     }
  276.                 }
  277.             }
  278.         }
  279.  
  280.     return (fContinue);
  281.     }
  282.  
  283. /*
  284.  * Builds a temporary string for output.  This string is padded with
  285.  * a space on the left and right
  286.  */
  287. VOLATILE SZ POPUP::SzFromCentPent(CENT cent,PENT pent)
  288.     {
  289.     PointerAssert(pent);
  290.     PointerAssert(pent[cent].sz);
  291.  
  292.     STATIC SZTEMP szAnswer = { " " };
  293.     CHAR chRight = (pent[cent].pentNext == pentNil) ? ' ' : 175;
  294.     CCH cch = strlen(pent[cent].sz);
  295.  
  296.     /*
  297.      * Build the temporary string.
  298.      *    After copy, pad the string with spaces.
  299.      */
  300.     strncpy(&szAnswer[1],pent[cent].sz,cch);
  301.  
  302.     while (cch < cchMenuMax)
  303.         szAnswer[1+cch++] = chSpace;
  304.     
  305.     /*
  306.      *    Finally, fill in the ending character..
  307.      */
  308.     szAnswer[cch+1] = chRight;
  309.     szAnswer[cch+2] = chNil;
  310.  
  311.     return (szAnswer);
  312.     }
  313.  
  314. /*
  315.  * Flash the selected entry
  316.  */
  317. VOID POPUP::Flash(CENT cent,PENT pent,WINDOW &rwnd)
  318.     {
  319.     for (INT count=0; count < 5; count++)
  320.         {
  321.         Display(cent,pent,rwnd,fFalse);
  322.         delay(40);
  323.         Display(cent,pent,rwnd,fTrue);
  324.         delay(40);
  325.         }
  326.     }
  327.  
  328. /*
  329.  * Windows dimensions..
  330.  */
  331. ROW POPUP::RowTopFromCentPent(CENT cent,PENT pent)
  332.     {
  333.     return (rowTop);
  334.     }
  335.  
  336. COL POPUP::ColLeftFromCentPent(CENT cent,PENT pent)
  337.     {
  338.     return (colLeft);
  339.     }
  340.  
  341. ROW POPUP::CrowFromCentPent(CENT centMac,PENT pent)
  342.     {
  343.     return (centMac);
  344.     }
  345.  
  346. COL POPUP::CcolFromCentPent(CENT centMac,PENT pent)
  347.     {
  348.     cchMenuMax = cchNil;
  349.  
  350.     Assert(pent != pentNil);
  351.  
  352.     for (CENT cent = centNil; cent < centMac; cent++)
  353.         {
  354.         Assert(pent[cent].sz != szNil);
  355.         cchMenuMax = Max(cchMenuMax,strlen(pent[cent].sz));
  356.         }
  357.  
  358.     return (cchMenuMax);
  359.     }
  360.  
  361. /*
  362.  *    Creates and activates a sub-menu for this object.
  363.  */
  364. BOOL POPUP::FSubMenuFromCentPent(CENT cent,PENT pent)
  365.     {
  366.     PENT pentSub = pent[cent].pentNext;
  367.     CENT centSub = pent[cent].centNext;
  368.     POPUP pop(rowTop+cent,colRight,centSub,pentSub,szNil);
  369.     BOOL fContinue = fTrue;
  370.  
  371.     /*
  372.      *    If the user "selects" the sub-menu, as opposed to ESCaping, then
  373.      *    we take that as this menu was selected also.
  374.      */
  375.     if (pop.CentGet() != centError)
  376.         fContinue = fFalse;
  377.  
  378.     return (fContinue);
  379.     }
  380.